#pragma once
#include <iostream>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <functional>
#include "Terminal.hpp"


typedef std::function<std::string(const std::string&)> func_t;//包装器

enum
{
    SOCKET_ERR=1,
    BIND_ERR=2,
};

const int size =1024;
uint16_t defaultport=8080;
std::string defaultip="0.0.0.0";

class UdpServer
{
public:
    UdpServer(const uint16_t& port=defaultport,const std::string& ip=defaultip)
        :_port(port)
        ,_ip(ip)
        ,_isrunning(false)
        ,_sockfd(0)
    {
    }

    ~UdpServer()
    {
       if(_sockfd>0)
       {
         close(_sockfd);
       } 
    }

    void Init()
    {
        //1.创建udp套接字sockfd
        _sockfd = socket(AF_INET,SOCK_DGRAM,0);//AF_INET == PF_INET
        if(_sockfd<0)
        {
            std::cout<<"socket create error!"<<std::endl;
            exit(SOCKET_ERR);
        }
        std::cout<<"socker create successfully! sockfd:"<<_sockfd<<std::endl;
        //2.bind 绑定socket
        //  2.1创建local,配置local
        struct sockaddr_in local;//-------为什么选择sockaddr_in?
        //记:ipv4用sockaddr_in类型 
        //配置local:置0,sin_family,sin_port,sin_addr.s_addr
        bzero(&local,sizeof(local));//------将local置0
        local.sin_family = AF_INET;//ip的类型-->ipv4
        local.sin_port=htons(_port);//端口号,需要发送给对方,但是规定要按大端传输网络字节序,所以要处理一下
        //local.sin_addr.s_addr=inet_addr(_ip.c_str());//ip地址,1.string->uint32_t  2.规范网络字节序
        local.sin_addr.s_addr= htonl(INADDR_ANY);
        //  2.2bind绑定
        int n = bind(_sockfd,(const struct sockaddr*)(&local),sizeof(local));
        if(n<0)
        {
            std::cout<<"socket bind fail!"<<std::endl;
            exit(BIND_ERR);
        }
        std::cout<<"bind successfully!"<<std::endl;
    }

    void Run(func_t func)//代码分层  func
    {
        _isrunning=true;
        char inbuffer[size];
        while(_isrunning)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            ssize_t n = recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,(struct sockaddr*)(&client),&len);
            //为什么这里_sockfd是服务器的sockfd
            if(n<0)
            {
                std::cout<<"recvfrom fail!"<<std::endl;
                continue;
            }
            std::cout<<"recvfrom successfully!"<<std::endl;
            inbuffer[n]=0;//当成字符串
            std::string info=inbuffer;
            std::string echo_string=func(info);

            sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,(const sockaddr*)&client,len);
            //为什么这里_sockfd是服务器的sockfd
        }
    }
private:
    int _sockfd;//网络文件描述符
    uint16_t _port;//服务器端口号
    std::string _ip;//ip地址
    bool _isrunning;//运行状态
};